/**
 * @file bsp_gsensor.c
 * @brief 
 * @author  ()
 * @version 1.0
 * @date 2024-09-13
 * 
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-13 <td>1.0     <td>     <td>内容
 * </table>
 */
#include "global.h"
#include "hal_adapter.h"
#include "sensor/sensor_support.h"
#include "sensor/sensor_wrapper.h"

#include "bsp_log.h"
#include "bsp_gsensor.h"


extern void Error_Handler(void);

SPI_HandleTypeDef gsensor_spi_ctx;


/// @brief gsensor 电源开启
/// @param
void gsensor_poweron(void)
{
    HAL_GPIO_WritePin(GSENSOR_PORT_PWR, GSENSOR_PIN_PWR, GPIO_PIN_RESET);
}

/// @brief gsensor 电源关闭
/// @param
void gsensor_poweroff(void)
{
    HAL_GPIO_WritePin(GSENSOR_PORT_PWR, GSENSOR_PIN_PWR, GPIO_PIN_SET);
}

bool bsp_gsensor_get_power_status(void)
{
    return (HAL_GPIO_ReadPin(GSENSOR_PORT_PWR, GSENSOR_PIN_PWR) == GPIO_PIN_RESET);
}


/// @brief gsensor 功能初始化
/// @param
/// @return
int32_t bsp_gsensor_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* gsensor power control, low availd */
    GPIO_InitStruct.Pin = GSENSOR_PIN_PWR;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GSENSOR_PORT_PWR, &GPIO_InitStruct);

    gsensor_poweroff();

    /* init spi port */
    gsensor_spi_ctx.Instance = GSENSOR_SPI_PERIHERAL;
    gsensor_spi_ctx.Init.Mode = SPI_MODE_MASTER;
    gsensor_spi_ctx.Init.Direction = SPI_DIRECTION_2LINES;
    gsensor_spi_ctx.Init.DataSize = SPI_DATASIZE_8BIT;
    gsensor_spi_ctx.Init.CLKPolarity = SPI_POLARITY_HIGH;
    gsensor_spi_ctx.Init.CLKPhase = SPI_PHASE_2EDGE;
    gsensor_spi_ctx.Init.NSS = SPI_NSS_SOFT;
    gsensor_spi_ctx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
    gsensor_spi_ctx.Init.FirstBit = SPI_FIRSTBIT_MSB;
    gsensor_spi_ctx.Init.TIMode = SPI_TIMODE_DISABLE;
    gsensor_spi_ctx.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    gsensor_spi_ctx.Init.CRCPolynomial = 0x7;
    gsensor_spi_ctx.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    gsensor_spi_ctx.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
    gsensor_spi_ctx.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
    gsensor_spi_ctx.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_01CYCLE;
    gsensor_spi_ctx.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_01CYCLE;
    gsensor_spi_ctx.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_ENABLE;
    gsensor_spi_ctx.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
    gsensor_spi_ctx.Init.IOSwap = SPI_IO_SWAP_DISABLE;
    gsensor_spi_ctx.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
    gsensor_spi_ctx.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;  
    if (HAL_SPI_Init(&gsensor_spi_ctx) != HAL_OK)
    {
        Error_Handler();
    }

	gsensor_int1_enable(NULL, NULL);
    
    /* GSENSOR Poweron */
    gsensor_poweron();

    /* GSENSOR Initial */
    sensor_initial();

    return 0;
}

/**
 * @brief spi片选使能
 */
void gsensor_spi_select(void)
{
    HAL_GPIO_WritePin(GSENSOR_PORT_NSS, GSENSOR_PIN_NSS, GPIO_PIN_RESET);
}

/**
 * @brief spi片选失能
 */
void gsensor_spi_deselect(void)
{
    HAL_GPIO_WritePin(GSENSOR_PORT_NSS, GSENSOR_PIN_NSS, GPIO_PIN_SET);
}

/**
 * @brief gsensor spi 写入
 * @param  data             My Param doc
 * @param  size             My Param doc
 * @return ssize_t 
 */
ssize_t gsensor_spi_write(const void *data, size_t size)
{
    int32_t ret = 0;

    // log_d("gsensor_spi_write,%d, %x\r\n", size, ((unsigned char *)data)[0]);
    ret = HAL_SPI_Transmit(&gsensor_spi_ctx, data, size, 1000);
    if(ret < 0)
    {
        return -EIO;
    }    
    // log_d("gsensor_spi_write finish, ret = %d\r\n", ret);
    return ret;
}

/**
 * @brief gsensor spi 读取
 * @param  data             My Param doc
 * @param  size             My Param doc
 * @return ssize_t 
 */
ssize_t gsensor_spi_read(void *data, size_t size)
{   
    int32_t ret = 0;

    // log_d("gsensor_spi_read\r\n");
    ret = HAL_SPI_Receive(&gsensor_spi_ctx, data, size, 1000);
    if(ret < 0)
    {
        return -EIO;
    }
    // log_d("gsensor_spi_read finish, ret = %d %x\r\n", ret, *(uint8_t *)data);

    return ret;
}

/**
 * @brief  打开 INT1 中断
 * @note   固定使用"上升沿"触发中断.
 * @param  isr: [I], 中断服务程序, 请将该ISR注册到 INT1 中断服务程序中;
 *         ptr: [I], 中断服务程序 isr 使用的 ptr.
 * @retval none
 */
void gsensor_int1_enable(void (*isr)(void *ptr), void *ptr)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
	/* GPIO Ports Clock Enable */
	__HAL_RCC_GPIOA_CLK_ENABLE();

	/*Configure GPIO pin : gsensor_int_Pin */
	GPIO_InitStruct.Pin = GSENSOR_PIN_INT;
	//GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
	//GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GSENSOR_PORT_INT, &GPIO_InitStruct);

	/* EXTI interrupt init*/
	HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(EXTI4_IRQn);
}

/**
 * @brief  关闭 INT1 中断
 */
void gsensor_int1_disable(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
	
    /* USER CODE BEGIN MX_GPIO_Init_1 */
	/* USER CODE END MX_GPIO_Init_1 */

	/* GPIO Ports Clock Enable */
	__HAL_RCC_GPIOA_CLK_ENABLE();

	/*Configure GPIO pin : gsensor_int_Pin */
	GPIO_InitStruct.Pin = GSENSOR_PIN_INT;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GSENSOR_PORT_INT, &GPIO_InitStruct);

	/* EXTI interrupt init*/
	HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0);
	HAL_NVIC_DisableIRQ(EXTI4_IRQn);
}

/**
 * @brief  其它进入睡眠模式的条件
 * @note   为了降低产品功耗, 原则上当设备静止时, sensor 需进入 sleep 模式,
 *         并使能 INT1 中断, 待达到运动阈值时, sensor 再唤醒并触发 INT1 中断,
 *         以便降低 sensor 的功耗; 但考虑到 sensor 判断"静止"的准确性, 以及某些
 *         场景下(比如行驶途中) sensor 不应自动进入 sleep 模式, 故增加此接口,
 *         用户可以利用该接口干预 sensor 的睡眠.
 * @retval true:静止时进入sleep模式, false:不可以进入sleep模式.
 */
bool gsensor_int1_extra_sleep_en(void)
{
    return true;
}


/**
 * @brief SPI MSP Initialization
 * This function configures the hardware resources used in this example
 * @param hspi: SPI handle pointer
 * @retval None
 */
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    if (hspi->Instance == GSENSOR_SPI_PERIHERAL)
    {
        /** Initializes the peripherals clock
         */
        gsensor_spiclk_enable();

        /*******************************************
         * PC10	SPI3_SCK	G-Sensor，SPI3_CLK
         * PC11	SPI3_MISO	G-Sensor，SPI3_MISO
         * PC12	SPI3_MOSI	G-Sensor，SPI3_MOSI
         * PA4	SPI3_NSS	连接到G_SENSOR  CS片选端；0-SPI通信模式，1-SPI空闲模式
         * PC8	OUTPUT	G_SENSOR 电源控制，0-打开电源;1-关闭电源
         ********************************************/
        GPIO_InitStruct.Pin = GSENSOR_PIN_SCK;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
        HAL_GPIO_Init(GSENSOR_PORT, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GSENSOR_PIN_MISO;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
        HAL_GPIO_Init(GSENSOR_PORT, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GSENSOR_PIN_MOSI;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
        HAL_GPIO_Init(GSENSOR_PORT, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GSENSOR_PIN_NSS;
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GSENSOR_PORT_NSS, &GPIO_InitStruct);

        /* SPI1 interrupt Init */
        // HAL_NVIC_SetPriority(GSENSOR_IRQn, 6, 0);

        // HAL_NVIC_EnableIRQ(GSENSOR_IRQn);
    }
}

/**
 * @brief SPI MSP De-Initialization
 * This function freeze the hardware resources used in this example
 * @param hspi: SPI handle pointer
 * @retval None
*/
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi)
{
    if (hspi->Instance == GSENSOR_SPI_PERIHERAL)
    {
        /* Peripheral clock disable */
        gsensor_spiclk_disable();

        /**SPI1 GPIO Configuration
        PC0     ------> SPI1_SCK
        PC2     ------> SPI1_MISO
        PC3     ------> SPI1_MOSI
        */
        HAL_GPIO_DeInit(GSENSOR_PORT, GSENSOR_PIN_SCK | GSENSOR_PIN_MISO | GSENSOR_PIN_MOSI);
        HAL_GPIO_DeInit(GSENSOR_PORT_NSS, GSENSOR_PIN_NSS);

        /* SPI1 interrupt DeInit */
        // HAL_NVIC_DisableIRQ(GSENSOR_IRQn);
    }
}



/**
 * @brief This function handles SPI3 global interrupt.
 */
void gsensor_irq_handler(void)
{
    HAL_SPI_IRQHandler(&gsensor_spi_ctx);
}

